﻿using System; 
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using Microsoft.Win32;
using System.IO;

namespace PT
{
	class RegistryReader
	{
		public static string GetRegistryValue(string subkey, string keyvalue)
		{
			RegistryKey mp = null;
			string path = string.Empty;

			try
			{
				mp = Registry.CurrentUser.OpenSubKey(subkey, /*writable*/ false);

				if (mp == null)
					return path;

				string value;
				if ((value = mp.GetValue(keyvalue) as string) != null)
					path = value;
			}
			finally
			{
			}

			mp.Close();
			return path;
		}

		public static string GetMaxPatrolLogsPath()
		{
			return GetRegistryValue("somepath", "somevalue");
		}

		public static string GetCustomPath()
		{
			return GetRegistryValue("Software\\kod.reader", "logpath");
		}

		public static string GetLogsPath()
		{
			string value;
			if (string.IsNullOrEmpty(value = GetMaxPatrolLogsPath()))
				value = GetCustomPath();

			return value;
		}
	}

	class TextReader
	{
		// copypasted from URL:
		// http://stackoverflow.com/questions/398378/get-last-10-lines-of-very-large-text-file-10gb-c
		public static string ReadEndTokens(string path, Int64 numberOfTokens, Encoding encoding, string tokenSeparator)
		{

			int sizeOfChar = encoding.GetByteCount("\n");
			byte[] buffer = encoding.GetBytes(tokenSeparator);


			using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))
			{
				Int64 tokenCount = 0;
				Int64 endPosition = fs.Length / sizeOfChar;

				for (Int64 position = sizeOfChar; position < endPosition; position += sizeOfChar)
				{
					fs.Seek(-position, SeekOrigin.End);
					fs.Read(buffer, 0, buffer.Length);

					if (encoding.GetString(buffer) == tokenSeparator)
					{
						tokenCount++;
						if (tokenCount == numberOfTokens)
						{
							byte[] returnBuffer = new byte[fs.Length - fs.Position];
							fs.Read(returnBuffer, 0, returnBuffer.Length);
							return encoding.GetString(returnBuffer);
						}
					}
				}

				// handle case where number of tokens in file is less than numberOfTokens
				fs.Seek(0, SeekOrigin.Begin);
				buffer = new byte[fs.Length];
				fs.Read(buffer, 0, buffer.Length);
				return encoding.GetString(buffer);
			}
		}
	}

	[ComVisible(true)]
	[InterfaceType(ComInterfaceType.InterfaceIsDual)]
	[Guid("06D8D4C1-94AE-468C-830B-A2E12B462A2C")]
	public interface ILogReader
	{
		string GetLinesAnsi(int count);
		string GetLinesUnicode(int count);
	}

	[ComVisible(true)]
	[ClassInterface(ClassInterfaceType.None)]
	[Guid("1DBD4D74-1F27-44C6-80B3-2C65271F1C8A")]
	[ProgId("kod.reader")]
	[ComDefaultInterface(typeof(ILogReader))]
	public class LogReader : ILogReader
	{
		string logFilename = null;
		long lastModifyTime = 0;
		int lastLinesCount = -1;

		private string GetLinesInternal(int count, Encoding enc)
		{
			if (count == 0)
				return "lines count is 0";

			if (logFilename == null)
				logFilename = RegistryReader.GetLogsPath();

			if (string.IsNullOrEmpty(logFilename))
				return "ERROR: can't get logs path";

			long modifyTime = 0;												 
			try
			{
				if ((modifyTime = File.GetLastWriteTime(logFilename).ToFileTime()) != lastModifyTime || 
					lastLinesCount != count)
				{
					lastModifyTime = modifyTime;
					lastLinesCount = count;
					return TextReader.ReadEndTokens(logFilename, count, enc, "\n");
				}
			}
			catch (Exception e)
            {
                return "Error: " + e.Message;
            }

			return string.Empty;
		}

		public string GetLinesAnsi(int count)										
		{
			return GetLinesInternal(count, Encoding.GetEncoding(1251));			
		}

		public string GetLinesUnicode(int count)										
		{
			return GetLinesInternal(count, Encoding.Unicode);			
		}
	}
}